/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.imgcog.filter;

import com.amd.aparapi.Kernel;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import technotheist.imgcog.image.Image;

/**
 *
 * @author Mitch
 */
public class RGBtoSphere {

    RGBtoSphereRunner runner;
    //azimuth = hue
    //radius = saturation
    //x,y = polartocart(azi, rad)
    //z = lightness-sign * lightness^2

    public Image convert(BufferedImage img) {
        boolean dirty = false;
        int i = 0, w = img.getWidth(), h = img.getHeight();
        //
        if (runner.imgData.length != w * h) {
            dirty = true;
            runner.output = new float[w * h * 3];
        }
        //
        runner.imgData = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
        runner.dims[0] = img.getWidth();
        runner.dims[1] = img.getHeight();
  
        runner.put(runner.imgData);
        runner.put(runner.dims);
        if (dirty) {
            runner.put(runner.output);
        }

        runner.run();
        runner.get(runner.output);
        return new Image(runner.output, w, h, 3);
    }

    protected class RGBtoSphereRunner extends Kernel {

        static final float RADIAN = 0.0174532925f;
        protected final int[] dims = new int[2];
        protected byte[] imgData;
        protected float[] output;

        @Override
        public void run() {
            int index = getGlobalId();
            int rgb = imgData[index];
            float r = ((rgb >> 16) & 0x000000FF) / 255f;
            float g = ((rgb >> 8) & 0x000000FF) / 255f;
            float b = ((rgb) & 0x000000FF) / 255f;

            float min = min(r, min(g, b));
            float max = max(r, max(g, b));
            float delta = max - min;
            float s = 0;
            float h = 0;
            if (delta > 0) {
                s = delta / max;
            }

            if (r == max) {
                h = (g - b) / delta;
            } else if (g == max) {
                h = 2 + (b - r) / delta;
            } else {
                h = 4 + (r - g) / delta;
            }
            h *= 60;
            if (h < 0) {
                h += 360;
            }
            h *= RADIAN;

            float i = 0, j = 0, k = 0;
            i = s * cos(h);
            j = s * sin(h);
            k = max * 2f - 1f;
            if (k >= 0) {
                k = sqrt(k);
            } else {
                k = -sqrt(-k);
            }

            int width = dims[0];
            int height = dims[1];
            int x = index%width;
            int y = index/width;
            index = x * height + y;
            
            output[index] = i;
            output[index + 1] = j;
            output[index + 2] = k;
        }
    }
}
